package com.bosicloud.cmb.ibp.edge.config;

import com.auth0.jwt.algorithms.Algorithm;
import com.bosicloud.cmb.ibp.commom.properties.EndpointProperties;
import com.bosicloud.cmb.ibp.edge.constant.HeaderKeys;
import com.bosicloud.cmb.ibp.edge.constant.UrlDefine;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.HeaderHttpSessionStrategy;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.Properties;

/**
 * @author Jack Peng / ziliang.peng@bosicloud.com
 */
@EnableRedisHttpSession
@Slf4j
@Configuration
@EnableConfigurationProperties( EndpointProperties.class )
public class CommonConfig extends WebMvcConfigurerAdapter {

    @Value("${server.error.path:${error.path:/error}}")
    private String errorPath;

    @Autowired
    private EndpointProperties properties;

    @Bean
    public static ConfigureRedisAction configureRedisAction() {
        return ConfigureRedisAction.NO_OP;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        template.setValueSerializer(new StringRedisSerializer());
        template.setDefaultSerializer(new StringRedisSerializer());

        return template;
    }

    @Bean
    public HttpSessionStrategy httpSessionStrategy() {
        HeaderHttpSessionStrategy strategy = new HeaderHttpSessionStrategy();
        strategy.setHeaderName(HeaderKeys.IBP_TOKEN);
        return strategy;
    }

    @Bean
    public DefaultKaptcha captchaProducer() {

        DefaultKaptcha captchaProducer = new DefaultKaptcha();
        Properties properties = new Properties();

        properties.setProperty("kaptcha.textproducer.char.length", "4");
        properties.setProperty("kaptcha.textproducer.font.size", "46");
        properties.setProperty("kaptcha.textproducer.font.color", "1,137,255");
        properties.setProperty("kaptcha.border", "no");
        properties.setProperty("kaptcha.textproducer.font.names", "DejaVu Serif");
        properties.setProperty("kaptcha.background.clear.from", "white");
        properties.setProperty("kaptcha.background.clear.to", "white");
        properties.setProperty("kaptcha.noise.color", "1,137,255");
        properties.setProperty("kaptcha.textproducer.char.space", "12");
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789SKPRHAM");

        Config config = new Config(properties);
        captchaProducer.setConfig(config);

        return captchaProducer;
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        super.addInterceptors(registry);

        registry.addInterceptor(new AuthIntercept()).
                addPathPatterns("/**").
                excludePathPatterns(UrlDefine.VERIFICATION_CODE).
                excludePathPatterns(UrlDefine.LOGIN_API).
                excludePathPatterns(UrlDefine.UPLOAD).
                excludePathPatterns(UrlDefine.DOWNLOAD_RES).
                excludePathPatterns(UrlDefine.GET_EC2_INSTANCE_TYPE).
                excludePathPatterns(errorPath).
                excludePathPatterns("/test").
                excludePathPatterns("/swagger-resources/**");

    }

    @Bean
    public Algorithm algorithm() {
        Algorithm algorithmHS = Algorithm.HMAC256(properties.getSecret());
        return algorithmHS;
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setMaxAge(60 * 60 * 24 * 30L);
        config.addExposedHeader(HeaderKeys.IBP_TOKEN);
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

    }

    @Override
    public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
    }


//    @Override
//    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
//        exceptionResolvers.add((request, response, handler, e) -> {
//
//            responseResult(response, null);
//            return new ModelAndView();
//        });
//    }

//    private void responseResult(HttpServletResponse response, UnionResult result) {
//        response.setCharacterEncoding("UTF-8");
//        response.setHeader("Content-type", "application/json;charset=UTF-8");
//        response.setStatus(200);
//        try {
//            response.getWriter().write(JSON.toJSONString(result));
//        } catch (IOException ex) {
//            log.error(ex.getMessage());
//        }
//    }
}
